package com.mofeng.myshop.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.mofeng.myshop.properties.FileProperty;
import com.mofeng.myshop.domain.po.Images;
import com.mofeng.myshop.domain.vo.base.PageMp;
import com.mofeng.myshop.domain.dto.base.SearchBaseMp;
import com.mofeng.myshop.exception.MyException;
import com.mofeng.myshop.mapper.ImagesMapper;
import com.mofeng.myshop.service.fileupload.FileServer;
import com.mofeng.myshop.service.ImageService;
import com.mofeng.myshop.service.fileupload.factory.FileFactory;
import com.mofeng.myshop.service.user.UserUtilsService;
import com.mofeng.myshop.service.user.impl.QrCodeServiceImpl;
import com.mofeng.myshop.until.*;
import com.mofeng.myshop.until.component.RedisUtil;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.TextUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Date;


@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class ImageServiceImpl implements ImageService {

    private final String separator = File.separator;

    private final FileProperty config;

    private final SnowflakeIdWorker idWorker;

    private final ImagesMapper imagesMapper;

    private final RedisUtil redisUtil;

    private final UserUtilsService userUtilsService;

    private final FileFactory factory;

    /**
     * 添加图片
     */
    @Override
    @Transactional
    public R addImage(MultipartFile imageFile) {
        try {
            if (imageFile == null) {
                return R.FAILED("图片不能为空。");
            }
            //判断类型
            String contentType = imageFile.getContentType();
            String originalFilename = imageFile.getOriginalFilename();
            if (TextUtils.isEmpty(contentType)) {
                return R.FAILED("图片格式错误。");
            }
            String type = getType(contentType, originalFilename);
            if (type == null) {
                return R.FAILED("不支持此图片格式。");
            }
            //限制大小
            long size = imageFile.getSize();
            if (size > config.getImageMaxSize()) {
                return R.FAILED("图片最大仅支持" + (config.getImageMaxSize() / 1024 / 1024) + "MB");
            }
            long imageId = idWorker.nextId();
            InputStream inputStream = imageFile.getInputStream();
            String md5 = MyUtil.MD5Util.calculateMD5(inputStream);
            Images images = imagesMapper.findByMd5(md5);
            if (images == null) {
                FileServer server = factory.getServer(config.getFileUploadType());
                String[] urlAndPath = server.saveFile(imageFile, config.getImagePath(), imageId + "");
                //保存数据到数据库
                images = new Images();
                images.setId(imageId);
                images.setUrl(urlAndPath[0]);
                images.setPath(urlAndPath[1]);
                images.setName(originalFilename);
                images.setOriginal("");
                images.setMd5(md5);
                images.setContentType(contentType);
                imagesMapper.insert(images);
            }
            return R.SUCCESS("图片上传成功。").setData(images.getUrl());
        } catch (Exception e) {
            throw new MyException("图片上传失败", e);
        }
    }

    /**
     * 获取图片
     */
    @Override
    public void getImage(String imageId) throws IOException {
        FileServer server = factory.getServer(config.getFileUploadType());
        server.getFile(config.getImagePath(), imageId);
    }

    /**
     * 获取图片列表
     */
    @Override
    public R imageList(SearchBaseMp searchMp) {
        Page<Images> pageResult = Db.lambdaQuery(Images.class)
                .like(searchMp.getKeyword() != null, Images::getOriginal, searchMp.getKeyword())
                .page(searchMp.getPageMp(Images.class));
        PageMp<Images> result = new PageMp<>(pageResult);
        return R.SUCCESS("查询图片成功。").setData(result);
    }

    /**
     * 获取文件类型
     */
    private String getType(String contentType, String fileName) {
        String type = null;
        if (Constants.ImageType.TYPE_JPG_PREFIX.equals(contentType)
                && fileName.endsWith(Constants.ImageType.TYPE_JPG)) {
            type = Constants.ImageType.TYPE_JPG;
        } else if (Constants.ImageType.TYPE_PNG_PREFIX.equals(contentType)
                && fileName.endsWith(Constants.ImageType.TYPE_PNG)) {
            type = Constants.ImageType.TYPE_PNG;
        } else if (Constants.ImageType.TYPE_JPEG_PREFIX.equals(contentType)
                && fileName.endsWith(Constants.ImageType.TYPE_JPG)) {
            type = Constants.ImageType.TYPE_JPG;
        } else if (Constants.ImageType.TYPE_GIF_PREFIX.equals(contentType)
                && fileName.endsWith(Constants.ImageType.TYPE_GIF)) {
            type = Constants.ImageType.TYPE_GIF;
        }
        return type;
    }

    /**
     * 删除图片
     */
    @Override
    @Transactional
    public R delImage(String imageId) {
        FileServer server = factory.getServer(config.getFileUploadType());
        String id = server.parseFileId(imageId);
        Images images = new Images();
        images.setId(Long.parseLong(id));
        images.setUpdateTime(new Date());
        imagesMapper.deleteById(images);
        server.delFile(config.getImagePath(), imageId);
        return R.SUCCESS("图片删除成功。");
    }

    /**
     * 获取二维码
     */
    @Override
    public void getQrCodeImage(String code) throws IOException {
        //检查二维码是否过期
        String loginState = (String) redisUtil.get(QrCodeServiceImpl.KEY_PC_LOGIN_CODE + code);
        if (TextUtils.isEmpty(loginState)) {
            //TODO:返回张图片 显示维码已经过期的
            return;
        }
        HttpServletRequest request = ServletUtils.getRequest();
        StringBuffer requestURL = request.getRequestURL();
        String servletPath = request.getServletPath();
        String originalDomain = requestURL.toString().replace(servletPath, "");
        //生成二维码
        //二维码内容是什么?
        //1、可以简单地是一个code ，也就是传进来这个
        //这各情况，如果是用自己的写的App来扫描，是识别并解析，请求对应的接口。
        //如果是第三方的就扫描，可以识别，但是没有用。只能显示这个code
        //2、应该一个APP下载地址code,如果是自己app到，切割后面的内容拿到code进行解析
        //请求对应接口，如果是第三方的app扫描，它是个网址，就会访问下载app的地址，去下载的app
        String content = originalDomain + Constants.APP_DOWNLOAD_PATH + "===" + code;
        byte[] qrCode = QrCodeUtils.encodeQRCode(content);
        HttpServletResponse response = ServletUtils.getResponse();
        response.setContentType(QrCodeUtils.RESPONSE_CONTENT_TYPE);
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(qrCode);
        outputStream.flush();
    }

}
